﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Web;
using System.IO;

namespace OviNotificationsApi
{

    /// <summary>
    /// Ovi Notifications API
    /// </summary>
    public class Notifications : RestBase, INotifications
    {

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="Notifications"/> class.
        /// </summary>
        /// <param name="baseUrl">The base URL.</param>
        /// <param name="apiVersion">The API version.</param>
        /// <param name="serviceID">The service ID.</param>
        /// <param name="serviceSecret">The service secret.</param>
        public Notifications(string baseUrl, string apiVersion, string serviceID, string serviceSecret)
        {
            this._baseUrl = baseUrl;
            this._apiVersion = apiVersion;
            this._serviceID = serviceID;
            this._serviceSecret = serviceSecret;
        }
        #endregion


        /// <summary>
        /// Sends the notification using notification ID.
        /// </summary>
        /// <param name="notificationId">The notification id.</param>
        /// <param name="wakeup">Specifies whether an application that is not already running on the device should be started when a notification is received. Note that a notification will only be displayed if the wake up parameter is set both in the Service API and the Client API.</param>
        /// <param name="payload">Notification content. Maximum length is 1536 bytes.</param>
        /// <param name="ctype">Specifies the content type as a mime-type (e.g., application/xml, text/plain). Maximum length is 255 bytes.</param>
        /// <param name="enc">Defines the message content encoding (e.g., Base64). Maximum length is 32 bytes.</param>
        public string SendNotification(string notificationId, bool? wakeup, string payload = "", string ctype = "", string enc = "")
        {
            #region Retrieve the endpoint and setup the request
            // Get the endpoint
            string endpoint = EndPoints[EndpointEnum.SendNotificationNid];

            // Substitute its parameters
            string notificationIdEncoded = HttpUtility.UrlEncode(HttpUtility.UrlEncode(notificationId)); // encoded twice because the request decodes it!!
            string finalEndpoint = BaseUrl + String.Format(endpoint, ApiVersion, notificationIdEncoded);

            HttpWebRequest request = SetupRequest(finalEndpoint, WebRequestMethods.Http.Post, this.ServiceID, this.ServiceSecret);
            #endregion

            #region Data to send
            // Add the data we want to send 
            Dictionary<string, string> parameters = new Dictionary<string, string>();
            if (wakeup.HasValue)
                this.AddPostParameter(parameters, "wakeup", wakeup.Value.ToString().ToLower());

            if (!string.IsNullOrEmpty(payload))
                this.AddPostParameter(parameters, "payload", payload);

            if (!string.IsNullOrEmpty(ctype))
                this.AddPostParameter(parameters, "ctype", ctype);

            if (!string.IsNullOrEmpty(enc))
                this.AddPostParameter(parameters, "enc", enc);
            #endregion

            // Process the data and append to request
            this.AppendPostParametersToRequest(request, parameters);

            #region Run the request and get the response
            try
            {
                // Get response  
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    Console.WriteLine("HTTP Response from Notifications API: " + response.StatusCode.ToString());
                    return response.StatusCode.ToString();
                }
            }
            catch (Exception ex)
            {
                throw new NotificationsApiException("HTTP POST Request to " + request.RequestUri.ToString() + " failed with error: " + ex.Message);
            } 
            #endregion
        }

        /// <summary>
        /// Sends the notification using JID + application ID.
        /// </summary>
        /// <param name="jid">The jid.</param>
        /// <param name="applicationId">The application id.</param>
        /// <param name="wakeup">Specifies whether an application that is not already running on the device should be started when a notification is received. Note that a notification will only be displayed if the wake up parameter is set both in the Service API and the Client API.</param>
        /// <param name="payload">Notification content. Maximum length is 1536 bytes.</param>
        /// <param name="ctype">Specifies the content type as a mime-type (e.g., application/xml, text/plain). Maximum length is 255 bytes.</param>
        /// <param name="enc">Defines the message content encoding (e.g., Base64). Maximum length is 32 bytes.</param>
        public string SendNotification(string jid, string applicationId, bool? wakeup, string payload = "", string ctype = "", string enc = "")
        {
            #region Retrieve the endpoint and setup the request
            // Get the endpoint
            string endpoint = EndPoints[EndpointEnum.SendNotificationJid];

            // Substitute its parameters
            string finalEndpoint = BaseUrl + String.Format(endpoint, ApiVersion, jid);

            HttpWebRequest request = SetupRequest(finalEndpoint, WebRequestMethods.Http.Post, this.ServiceID, this.ServiceSecret);
            #endregion

            #region Data to send
            // Add the data we want to send 
            Dictionary<string, string> parameters = new Dictionary<string, string>();

            this.AddPostParameter(parameters, "toapp", applicationId);

            if (wakeup.HasValue)
                this.AddPostParameter(parameters, "wakeup", wakeup.Value.ToString().ToLower());

            if (!string.IsNullOrEmpty(payload))
                this.AddPostParameter(parameters, "payload", payload);

            if (!string.IsNullOrEmpty(ctype))
                this.AddPostParameter(parameters, "ctype", ctype);

            if (!string.IsNullOrEmpty(enc))
                this.AddPostParameter(parameters, "enc", enc);
            #endregion

            // Process the data and append to request
            this.AppendPostParametersToRequest(request, parameters);

            #region Run the request and get the response
            try
            {
                // Get response  
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    Console.WriteLine("HTTP Response from Notifications API: " + response.StatusCode.ToString());
                    return response.StatusCode.ToString();
                }
            }
            catch (Exception ex)
            {
                throw new NotificationsApiException("HTTP POST Request to " + request.RequestUri.ToString() + " failed with error: " + ex.Message);
            }
            #endregion
        }

        /// <summary>
        /// Gets the API version.
        /// </summary>
        public string Version()
        {
            #region Retrieve the endpoint and setup the request
            // Get the endpoint
            string endpoint = EndPoints[EndpointEnum.Version];

            // Substitute its parameters
            string finalEndpoint = BaseUrl + endpoint;

            HttpWebRequest request = SetupRequest(finalEndpoint, WebRequestMethods.Http.Get, this.ServiceID, this.ServiceSecret);
            #endregion

            #region Run the request and get the response
            try
            {
                // Get response  
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    Console.WriteLine("HTTP Response from Notifications API: " + response.StatusCode.ToString());

                    // Get the response stream  
                    StreamReader reader = new StreamReader(response.GetResponseStream());

                    // Console application output  
                    return reader.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                throw new NotificationsApiException("HTTP GET Request to " + request.RequestUri.ToString() + " failed with error: " + ex.Message);
            }
            #endregion
        }

        /// <summary>
        /// Pings the service.
        /// </summary>
        public string PingService()
        {
            #region Retrieve the endpoint and setup the request
            // Get the endpoint
            string endpoint = EndPoints[EndpointEnum.PingService];

            // Substitute its parameters
            string finalEndpoint = BaseUrl + String.Format(endpoint, ApiVersion);

            HttpWebRequest request = SetupRequest(finalEndpoint, WebRequestMethods.Http.Get, this.ServiceID, this.ServiceSecret);
            #endregion

            #region Run the request and get the response
            try
            {
                // Get response  
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    Console.WriteLine("HTTP Response from Notifications API: " + response.StatusCode.ToString());
                    return response.StatusCode.ToString();
                }
            }
            catch (Exception ex)
            {
                throw new NotificationsApiException("HTTP GET Request to " + request.RequestUri.ToString() + " failed with error: " + ex.Message);
            }
            #endregion
        }

        /// <summary>
        /// Pings the client using JID + application ID.
        /// </summary>
        public string PingClient(string jid, string applicationId)
        {
            #region Retrieve the endpoint and setup the request
            // Get the endpoint
            string endpoint = EndPoints[EndpointEnum.PingClientJidAppId];

            // Substitute its parameters
            string finalEndpoint = BaseUrl + String.Format(endpoint, ApiVersion, jid, applicationId);

            HttpWebRequest request = SetupRequest(finalEndpoint, WebRequestMethods.Http.Get, this.ServiceID, this.ServiceSecret);
            #endregion

            #region Run the request and get the response
            try
            {
                // Get response  
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    Console.WriteLine("HTTP Response from Notifications API: " + response.StatusCode.ToString());
                    return response.StatusCode.ToString();
                }
            }
            catch (Exception ex)
            {
                throw new NotificationsApiException("HTTP GET Request to " + request.RequestUri.ToString() + " failed with error: " + ex.Message);
            }
            #endregion
        }

        /// <summary>
        /// Pings the client using notification ID.
        /// </summary>
        public string PingClient(string notificationId)
        {
            #region Retrieve the endpoint and setup the request
            // Get the endpoint
            string endpoint = EndPoints[EndpointEnum.PingClientNid];

            // Substitute its parameters
            string notificationIdEncoded = HttpUtility.UrlEncode(HttpUtility.UrlEncode(notificationId)); // encoded twice because the request decodes it!!            
            string finalEndpoint = BaseUrl + String.Format(endpoint, ApiVersion, notificationIdEncoded);

            HttpWebRequest request = SetupRequest(finalEndpoint, WebRequestMethods.Http.Get, this.ServiceID, this.ServiceSecret);
            #endregion
            
            #region Run the request and get the response
            try
            {
                // Get response  
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    Console.WriteLine("HTTP Response from Notifications API: " + response.StatusCode.ToString());
                    return response.StatusCode.ToString();
                }
            }
            catch (Exception ex)
            {
                throw new NotificationsApiException("HTTP GET Request to " + request.RequestUri.ToString() + " failed with error: " + ex.Message);
            }
            #endregion
        }

        /// <summary>
        /// Gets the query limitations.
        /// </summary>
        public string QueryLimitations()
        {
            #region Retrieve the endpoint and setup the request
            // Get the endpoint
            string endpoint = EndPoints[EndpointEnum.QueryLimits];

            // Substitute its parameters
            string finalEndpoint = BaseUrl + String.Format(endpoint, ApiVersion);

            HttpWebRequest request = SetupRequest(finalEndpoint, WebRequestMethods.Http.Get, this.ServiceID, this.ServiceSecret);
            #endregion

            #region Run the request and get the response
            try
            {
                // Get response  
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    Console.WriteLine("HTTP Response from Notifications API: " + response.StatusCode.ToString());

                    // Get the response stream  
                    StreamReader reader = new StreamReader(response.GetResponseStream());

                    // Console application output  
                    return reader.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                throw new NotificationsApiException("HTTP GET Request to " + request.RequestUri.ToString() + " failed with error: " + ex.Message);
            }
            #endregion
        }
    }
}
